package com.deng.framework.aop.framework;

import com.deng.framework.aop.AdvisedSupport;
import org.aopalliance.intercept.MethodInterceptor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * JDK方法来实现动态代理,是AOP的一个核心类
 *  这里使用的是经典的Proxy方法实现JDK动态代理
 */
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {

    private final AdvisedSupport advisedSupport;

    public JdkDynamicAopProxy(AdvisedSupport advisedSupport) {
        this.advisedSupport = advisedSupport;
    }

    /**
     * 动态代理的核心函数，本质上是用了Proxy这个专门用来做动态代理的轮子，动态代理就是在使用TargetSource的某个函数时会随时注入我们的自定义方法
     * ps：值得注意的是该方法返回的是一个Object，即目标类TargetSource，所以在后面AOP融合spring的时候，需要被AOP动态代理的类就没有走bean的实例化~bean的初始化了，
     * 而是使用JDK方法实现了其bean的实例化等一系列操作，但注意还是需要将其存入实例化map中，毕竟被AOP代理的类仍然是spring的一个bean
     */
    @Override
    public Object getProxy() {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), advisedSupport.getTargetSource().getTargetClass(), this);
    }

    /**
     * 实现动态代理的核心函数，其实本质上就是在运行的时候如果有人调用advisedSupport中的目标类的函数，
     * jdk就会将其动态代理到这个函数进行方法匹配，如果匹配成功，则先执行执行methodInterceptor中的方法
     * 如果没成功就只执行原目标类的方法
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if(advisedSupport.getMethodMatcher().matches(method, advisedSupport.getTargetSource().getTarget().getClass())){
            MethodInterceptor methodInterceptor = advisedSupport.getMethodInterceptor();
            // 调用我们methodInterceptor中自定义的方法
            // 本来使用invoke就行了，这里是对invoke的传入参数MethodInvocation进行了包装，详见ReflectiveMethodInvocation类
            return methodInterceptor.invoke(new ReflectiveMethodInvocation(advisedSupport.getTargetSource().getTarget(), method, args));
        }
        //调用原本目标类中的目标方法
        return method.invoke(advisedSupport.getTargetSource().getTarget(), args);
    }
}
